﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using SealightCaching = Sealight.API.Framework.Caching;

using Microsoft.Practices.EnterpriseLibrary.Caching;
using Microsoft.Practices.EnterpriseLibrary.Caching.Expirations;
namespace Sealight.CoreAPI
{
   public class EntlibCacheService: IEntlibCacheService
    {
       private ICacheManager cacheManager = null;
       public EntlibCacheService(ICacheManager cacheManager)
        {
            this.cacheManager = cacheManager;
        }
        #region ICacheProvider Members

        public void Add(string key, object value)
        {
            this.cacheManager.Add(key, value);
        }

        public void Add(string key, object value, SealightCaching.CacheItemPriority scavengingPriority, SealightCaching.ICacheItemRefreshAction refreshAction, params SealightCaching.ICacheItemExpiration[] expirations)
        {
            cacheManager.Add(key, value, ConvertCacheItemPriority(scavengingPriority), ConvertRefreshAction(refreshAction), ConvertExpirations(expirations));
        }

        public bool Contains(string key)
        {
            return cacheManager.Contains(key);
        }

        public int Count
        {
            get { return cacheManager.Count; }
        }

        public void Flush()
        {
            cacheManager.Flush();
        }

        public object Get(string key)
        {
            return cacheManager.GetData(key);
        }

        public void Remove(string key)
        {
            cacheManager.Remove(key);
        }

        public object this[string key]
        {
            get { return cacheManager[key]; }
        }

        #endregion
        /// <summary>
        /// Converts the cache item priority.
        /// </summary>
        /// <param name="priority">The priority.</param>
        /// <returns></returns>
        private CacheItemPriority ConvertCacheItemPriority(SealightCaching.CacheItemPriority priority)
        {
            switch (priority)
            {
                case SealightCaching.CacheItemPriority.None:
                    return CacheItemPriority.None;                   
                case SealightCaching.CacheItemPriority.Low:
                    return CacheItemPriority.Low;                  
                case SealightCaching.CacheItemPriority.Normal:
                    return CacheItemPriority.Normal;                   
                case SealightCaching.CacheItemPriority.High:
                    return CacheItemPriority.High;                   
                case SealightCaching.CacheItemPriority.NotRemovable:
                    return CacheItemPriority.NotRemovable;                    
                default:
                    return CacheItemPriority.None;
                   
            }
        }
        /// <summary>
        /// Converts the refresh action.
        /// </summary>
        /// <param name="priority">The priority.</param>
        /// <returns></returns>
        private ICacheItemRefreshAction ConvertRefreshAction(SealightCaching.ICacheItemRefreshAction refreshAction)
        {
            if (refreshAction == null)
            {
                return null;
            }
            return new RefreshActionWrapper(refreshAction);
        }
        /// <summary>
        /// Converts the expirations.
        /// </summary>
        /// <param name="expirations">The expirations.</param>
        /// <returns></returns>
        private ICacheItemExpiration[] ConvertExpirations(SealightCaching.ICacheItemExpiration[] expirations)
        {
            ICacheItemExpiration[] cacheItemExpirations = new ICacheItemExpiration[expirations.Length];
            for (int i = 0; i < expirations.Length; i++)
            {
                cacheItemExpirations[i] = ConvertExpiration(expirations[i]);
            }
            return cacheItemExpirations;
        }
        /// <summary>
        /// Converts the expiration.
        /// </summary>
        /// <param name="expiration">The expiration.</param>
        /// <returns></returns>
        private ICacheItemExpiration ConvertExpiration(SealightCaching.ICacheItemExpiration expiration)
        {
            if (expiration is SealightCaching.AbsoluteTime)
            {
                return new AbsoluteTime(((SealightCaching.AbsoluteTime)expiration).ExpirationTime);
            }
            if (expiration is SealightCaching.FileDependency)
            {
                return new FileDependency(((SealightCaching.FileDependency)expiration).FileName);
            }
            if (expiration is SealightCaching.SlidingTime)
            {
                return new SlidingTime(((SealightCaching.SlidingTime)expiration).SlidingExpiration);
            }
            if (expiration is SealightCaching.NeverExpired)
            {
                return new NeverExpired();
            }
            if (expiration is SealightCaching.DirectoryDependency)
            {
                SealightCaching.DirectoryDependency dependency = (SealightCaching.DirectoryDependency)expiration;
                return new Sealight.CoreAPI.Caching.DirectoryDependency(dependency.DirectoryName);
            }
            return null;
        }
    }

    class RefreshActionWrapper : ICacheItemRefreshAction
    {
        private SealightCaching.ICacheItemRefreshAction refreshAction = null;
        /// <summary>
        /// Initializes a new instance of the <see cref="RefreshActionWrapper"/> class.
        /// </summary>
        /// <param name="refreshAction">The refresh action.</param>
        public RefreshActionWrapper(SealightCaching.ICacheItemRefreshAction refreshAction)
        {
            this.refreshAction = refreshAction;
        }
        #region ICacheItemRefreshAction Members

        /// <summary>
        /// Called when an item expires from the cache. This method can be used to notify an application that
        /// the expiration occured, cause the item to be refetched and refreshed from its original location, or
        /// perform any other application-specific action.
        /// </summary>
        /// <param name="removedKey">Key of item removed from cache. Will never be null.</param>
        /// <param name="expiredValue">Value from cache item that was just expired</param>
        /// <param name="removalReason">Reason the item was removed from the cache. See <see cref="T:Microsoft.Practices.EnterpriseLibrary.Caching.CacheItemRemovedReason"/></param>
        /// <remarks>This method should catch and handle any exceptions thrown during its operation. No exceptions should leak
        /// out of it.</remarks>
        public void Refresh(string removedKey, object expiredValue, CacheItemRemovedReason removalReason)
        {
            this.refreshAction.Refresh(removedKey, expiredValue, ConvertRemovedReason(removalReason));
        }

        #endregion

        private SealightCaching.CacheItemRemovedReason ConvertRemovedReason(CacheItemRemovedReason removalReason)
        {
            switch (removalReason)
            {
                case CacheItemRemovedReason.Expired:
                    return SealightCaching.CacheItemRemovedReason.Expired;
                  
                case CacheItemRemovedReason.Removed:
                    return SealightCaching.CacheItemRemovedReason.Removed;
                   
                case CacheItemRemovedReason.Scavenged:
                    return SealightCaching.CacheItemRemovedReason.Scavenged;
                  
                case CacheItemRemovedReason.Unknown:
                    return SealightCaching.CacheItemRemovedReason.Unknown;
                   
                default:
                    return SealightCaching.CacheItemRemovedReason.Expired;
                   
            }
        }
    }
}
